package com.hs.srm.admin.modules.sys.shiro;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Component;

import com.hs.srm.base.common.utils.Constant;
import com.hs.srm.base.modules.sys.dao.SysMenuDao;
import com.hs.srm.base.modules.sys.dao.SysUserDao;
import com.hs.srm.base.modules.sys.entity.SysMenuEntity;
import com.hs.srm.base.modules.sys.entity.SysUserEntity;
import com.hs.srm.base.modules.sys.shiro.ShiroUtils;
import com.hs.srm.common.utils.DozerUtil;

/**
 * 认证
 * 
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2016年11月10日 上午11:55:49
 */
@Component
public class UserRealm extends AuthorizingRealm {
	@Resource
	private SysUserDao sysUserDao;
	@Resource
	private SysMenuDao sysMenuDao;

	/**
	 * 重写密码校验规则：使用spring-security的密码校验
	 * @param authcToken
	 * @param info
	 * @throws AuthenticationException
	 */
	@Override
	public void assertCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info)
			throws AuthenticationException {
//		MyUsernamePasswordToken token = (MyUsernamePasswordToken)authcToken;
//		SysUserEntity user = DozerUtil.map(info.getPrincipals().getPrimaryPrincipal(), SysUserEntity.class);
//		ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder(1);
//		if(!passwordEncoder.isPasswordValid(user.getPassword(), String.valueOf(token.getPassword()), user.getSalt())) {
//			String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
//			throw new IncorrectCredentialsException(msg);
//		}
		
		super.assertCredentialsMatch(authcToken, info);
	}

	/**
	 * 认证(登录时调用)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		MyUsernamePasswordToken token = (MyUsernamePasswordToken)authcToken;

		// 查询用户信息
		SysUserEntity user = new SysUserEntity();
		user.setUsername(token.getUsername());
		user = this.sysUserDao.selectOne(user);

		// 账号不存在
		if(user == null) {
			throw new UnknownAccountException("账号或密码不正确");
		}

		// 账号锁定
		if(user.getStatus().intValue() == 0) {
			throw new LockedAccountException("账号已被锁定,请联系管理员");
		}

		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(),
				ByteSource.Util.bytes(user.getSalt()), this.getName());
		return info;
	}

	/**
	 * 授权(验证权限时调用)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SysUserEntity user = DozerUtil.map(principals.getPrimaryPrincipal(), SysUserEntity.class);
		Long userId = user.getUserId();

		List<String> permsList;

		// 系统管理员，拥有最高权限
		if(userId.intValue() == Constant.SUPER_ADMIN) {
			List<SysMenuEntity> menuList = this.sysMenuDao.selectList(null);
			permsList = new ArrayList<>(menuList.size());
			for(SysMenuEntity menu : menuList) {
				permsList.add(menu.getPerms());
			}
		} else {
			permsList = this.sysUserDao.queryAllPerms(userId);
		}

		// 用户权限列表
		Set<String> permsSet = new HashSet<>();
		for(String perms : permsList) {
			if(StringUtils.isBlank(perms)) {
				continue;
			}
			permsSet.addAll(Arrays.asList(perms.trim().split(",")));
		}

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setStringPermissions(permsSet);
		return info;
	}

	@Override
	public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
		HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
		shaCredentialsMatcher.setHashAlgorithmName(ShiroUtils.hashAlgorithmName);
		shaCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations);
		super.setCredentialsMatcher(shaCredentialsMatcher);
	}

	@Override
	public boolean supports(AuthenticationToken authenticationToken) {
		return authenticationToken instanceof MyUsernamePasswordToken;
	}
}
